package nl.hanze.security;

public class AESE {
    /* in this setting keysize is always 128 bits and blocksize 128 bits */
    private int[] iExpKey;
    int[] T0={
        -1520213050,-2072216328,-1720223762,-1921287178,234025727,-1117033514,-1318096930,1422247313,1345335392,50397442,-1452841010,2099981142,436141799,1658312629,-424957107,-1703512340,
         1170918031,-1652391393,1086966153,-2021818886,368769775,-346465870,-918075506,200339707,-324162239,1742001331,-39673249,-357585083,-1080255453,-140204973,-1770884380,1539358875,
         -1028147339,486407649,-1366060227,1780885068,1513502316,1094664062,49805301,1338821763,1546925160,-190470831,887481809,150073849,-1821281822,1943591083,1395732834,1058346282,
         201589768,1388824469,1696801606,1589887901,672667696,-1583966665,251987210,-1248159185,151455502,907153956,-1686077413,1038279391,652995533,1764173646,-843926913,-1619692054,
         453576978,-1635548387,1949051992,773462580,756751158,-1301385508,-296068428,-73359269,-162377052,1295727478,1641469623,-827083907,2066295122,1055122397,1898917726,-1752923117,
         -179088474,1758581177,0,753790401,1612718144,536673507,-927878791,-312779850,-1100322092,1187761037,-641810841,1262041458,-565556588,-733197160,-396863312,1255133061,
         1808847035,720367557,-441800113,385612781,-985447546,-682799718,1429418854,-1803188975,-817543798,284817897,100794884,-2122350594,-263171936,1144798328,-1163944155,-475486133,
         -212774494,-22830243,-1069531008,-1970303227,-1382903233,-1130521311,1211644016,83228145,-541279133,-1044990345,1977277103,1663115586,806359072,452984805,250868733,1842533055,
         1288555905,336333848,890442534,804056259,-513843266,-1567123659,-867941240,957814574,1472513171,-223893675,-2105639172,1195195770,-1402706744,-413311558,723065138,-1787595802,
         -1604296512,-1736343271,-783331426,2145180835,1713513028,2116692564,-1416589253,-2088204277,-901364084,703524551,-742868885,1007948840,2044649127,-497131844,487262998,1994120109,
         1004593371,1446130276,1312438900,503974420,-615954030,168166924,1814307912,-463709000,1573044895,1859376061,-273896381,-1503501628,-1466855111,-1533700815,937747667,-1954973198,
         854058965,1137232011,1496790894,-1217565222,-1936880383,1691735473,-766620004,-525751991,-1267962664,-95005012,133494003,636152527,-1352309302,-1904575756,-374428089,403179536,
         -709182865,-2005370640,1864705354,1915629148,605822008,-240736681,-944458637,1371981463,602466507,2094914977,-1670089496,555687742,-582268010,-591544991,-2037675251,-2054518257,
         -1871679264,1111375484,-994724495,-1436129588,-666351472,84083462,32962295,302911004,-1553899070,1597322602,-111716434,-793134743,-1853454825,1489093017,656219450,-1180787161,
         954327513,335083755,-1281845205,856756514,-1150719534,1893325225,-1987146233,-1483434957,-1231316179,572399164,-1836611819,552200649,1238290055,-11184726,2015897680,2061492133,
         -1886614525,-123625127,-2138470135,386731290,-624967835,837215959,-968736124,-1201116976,-1019133566,-1332111063,1999449434,286199582,-877612933,-61582168,-692339859,974525996
           };

    public AESE(int[] iKey) {
        int i, temp1, temp2;
        iExpKey = new int[44];
        for(i=0;i<4;i++) iExpKey[i]=iKey[i];
        for(i=4;i<44;i++) {
            temp1=iExpKey[i-1];
            if (i%4==0) {
                temp2=(temp1<<8)|(temp1>>>24);
                temp1=((T0[temp2>>>24]>>8)&0xff)<<24|((T0[(temp2>>16)&0xff]>>8)&0xff)<<16|((T0[(temp2>>8)&0xff]>>8)&0xff)<<8|((T0[temp2&0xff]>>8)&0xff);
                temp1^=1<<(23+i/4);
            }
            iExpKey[i]=iExpKey[i-4]^temp1;
        }
    }

    public final int [] ECB(int[] iBlock) {
        int[] iA=new int[4];
        int[] iB=new int[4];
        int i, j, l, iTemp;

        // initial key adding
        for(i=0;i<4;i++) iA[i]=iBlock[i]^iExpKey[i];

        // 9 standard rounds
        for(i=1;i<=9;i++) {
            for(j=0;j<4;j++) { // each column
                iTemp=0;
                for(l=0;l<4;l++)  // each row
                    iTemp=T0[(iA[(j+l+1)%4]>>(8*(3-l)))&0xff] ^ ((iTemp>>>24)|(iTemp<<8));
                iB[j]=iExpKey[4*i+j]^iTemp;
            }
        for(j=0;j<4;j++) iA[j]=iB[j];
        }
        // final round
        for(j=0;j<4;j++)
            iB[j]=iExpKey[40+j]^((((T0[(iA[(j+1)%4]>>24)&0xff]>>8)&0xff)<<24)|(((T0[(iA[(j+2)%4]>>16)&0xff]>>8)&0xff)<<16)|(((T0[(iA[(j+3)%4]>>8)&0xff]>>8)&0xff)<<8)|((T0[iA[j]&0xff]>>8)&0xff));
        return iB;
    }
}
